package com.website.dayouziblog.serviceImpl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.website.dayouziblog.exception.BaseErrorEnum;
import com.website.dayouziblog.exception.BaseException;
import com.website.dayouziblog.mapper.dayouziblog.ArticleMapper;
import com.website.dayouziblog.mapper.informationSchema.ArticleTotalsMapper;
import com.website.dayouziblog.model.DO.ArticleDO;
import com.website.dayouziblog.model.DTO.ArticleDTO;
import com.website.dayouziblog.model.VO.ArticleVO;
import com.website.dayouziblog.model.entity.PageBean;
import com.website.dayouziblog.service.ArticleService;
import com.website.dayouziblog.utils.TimeUtil;
import com.website.dayouziblog.utils.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class ArticleServiceImpl implements ArticleService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ArticleServiceImpl.class);

    @Resource
    private ArticleMapper articleMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private ArticleTotalsMapper articleTotalsMapper;

    @Resource(name = "defaultThreadPool")
    private ThreadPoolTaskExecutor executor;

    @Value("${key.article_expireTime}")
    private Integer article_expireTime;


    @Override
    public boolean addArticle(ArticleDTO articleDTO) {
        //获取当前时间
        String time = TimeUtil.getDateTime(new Date());
        //判断是否有发布时间
        if (StringUtils.isEmpty(articleDTO.getPubtime())) {
            articleDTO.setPubtime(time);
        }
        articleDTO.setLastUpdateTime(time);
        redisTemplate.delete("Article:HotInfo");
        redisTemplate.delete("Article:Order");
        return articleMapper.addArticle(articleDTO);
    }

    @Override
    public boolean deleteArticle(Integer id) {
        //判断文章id是否存在
        if (!articleMapper.isExists(id)) {
            throw new BaseException(BaseErrorEnum.NOT_FOUND);
        }
        //删除文章
        redisTemplate.delete("Article:HotInfo");
        redisTemplate.delete("Article:Order");
        return articleMapper.deleteArticle(id);
    }

    @Override
    public boolean updateArticle(ArticleDTO articleDTO) {
        //判断文章id是否存在
        if (!articleMapper.isExists(articleDTO.getId())) {
            throw new BaseException(BaseErrorEnum.NOT_FOUND);

        }
        //修改文章
        articleDTO.setLastUpdateTime(TimeUtil.getDateTime(new Date()));
        redisTemplate.delete("Article:HotInfo");
        redisTemplate.delete("Article:Order");
        return articleMapper.updateArticle(articleDTO);
    }

    @Override
    public PageBean findAllArticle(Integer page, Integer pageSize) {
        //查询第一页的时候进redis缓存，后续页码进mysql
        List<ArticleVO> listValue = new ArrayList<>();
        if (page == 1) {
            //从redis获取所有article相关的key
            //获取发布时间排序最新的数据的id
            Set<Object> idSet = redisTemplate.opsForZSet().reverseRange("Article:Order", 0, pageSize - 1);
            for (Object oid : idSet) {
                //通过id获取数据详情
                String id = String.valueOf(oid);
                Object o = redisTemplate.opsForHash().get("Article:HotInfo", id);
                //取值时对o进行解析处理
                String parse = (String) JSON.parse(JSONObject.toJSONString(o));
                ArticleVO articleVO = JSONObject.parseObject(parse, ArticleVO.class);
                if (articleVO != null) {
                    listValue.add(articleVO);
                }
            }
            if (listValue.size() > 0) {
                //获取文章总数
//                Map map = articleTotalsMapper.getArticleTotals("article");
//                String t = map.get("total").toString();
//                int num = Integer.parseInt(t);


                //封装返回
                PageBean pageBean = new PageBean(listValue);
                pageBean.setTotal(listValue.size());
                pageBean.setPageNum(page);
                pageBean.setPageSize(pageSize);
                LOGGER.info("redis获取数据成功!");
                return pageBean;
            }
        }

        //redis中没获取到，就从mysql获取
        PageInfo<ArticleDO> pageInfo = PageHelper.startPage(page, pageSize).doSelectPageInfo(() -> {
            articleMapper.findAllArticle();
        });
        long total = pageInfo.getTotal();
        List<ArticleDO> articleDOList = pageInfo.getList().stream().collect(Collectors.toList());

        //处理数据
        for (ArticleDO articleDO : articleDOList) {
            ArticleVO articleVO = JSONObject.parseObject(JSONObject.toJSONString(articleDO), ArticleVO.class);
            //只缓存第一页的数据
            if (page == 1) {
                //存入info
                redisTemplate.opsForHash().put("Article:HotInfo", JSONObject.toJSONString(articleVO.getId()),
                        JSONObject.toJSONString(articleVO));
                //存入排序
                Double score = Double.valueOf(TimeUtil.dateTotimeStamp(articleVO.getPubtime()));
                redisTemplate.opsForZSet().add("Article:Order", JSONObject.toJSONString(articleVO.getId()), score);

                //设置过期时间
                redisTemplate.expire("Article:HotInfo", 1800, TimeUnit.SECONDS);
                redisTemplate.expire("Article:Order", 1800, TimeUnit.SECONDS);
            }
            //存入返回用list
            listValue.add(articleVO);
        }

        //返回
        PageBean<ArticleVO> pageBean = new PageBean<>(listValue);
        pageBean.setTotal(total);
        LOGGER.info("mysql获取数据成功!");
        return pageBean;
    }

    @Override
//    @Async("defaultThreadPool")
    public void testAsync() {
        t1();
        executor.execute(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " 123");

        });
        t1();

    }

    private void t1() {
        System.out.println(Thread.currentThread().getName() + "11111");
    }

}
